

#include "DBManager/Repository/HDF5/Input/Coordinate/TRANSFORMATIONRepository.h"

#include "DBManager/Repository/HDF5/Base/HDF5RepositoryMacro.h"

HDF5_REG_REPOSITORY (TRANSFORMATIONRepository)

using namespace SG::DBManager::HDF5;
using namespace SG::DataStructure;
using namespace SG::DataStructure::FEM;
using namespace SG::DataStructure::Common;

// 构造函数实现
TRANSFORMATIONRepository::TRANSFORMATIONRepository (HDF5Database& database)
    : SG::DBManager::HDF5::MainlyRepositoryBase<MainStruct> (database)
{}

void TRANSFORMATIONRepository::InitialDatasetInfo ()
{
    RegisterTableInfo<SG::DataStructure::Common::Id> ("/OWN/INDEX/INPUT/COORDINATE_SYSTEM/TRANSFORMATION", IndexDataset);
    RegisterTableInfo<NasMainStruct> ("/SG/INPUT/COORDINATE_SYSTEM/TRANSFORMATION/IDENTITY", MainDataset);
    RegisterTableInfo<SubStructIDATA> ("/SG/INPUT/COORDINATE_SYSTEM/TRANSFORMATION/IDATA", SubDataset_IDATA);
    RegisterTableInfo<SubStructRDATA> ("/SG/INPUT/COORDINATE_SYSTEM/TRANSFORMATION/RDATA", SubDataset_RDATA);
}

void TRANSFORMATIONRepository::DumpWriteCahce ()
{
    auto& writeStorage = this->GetMainCache ().m_writeStorage;

    // 1. flag设置为无顺序
    GetMainDatasetInfo ().SetIsSequential (false);

    // 主表数据
    std::vector<NasMainStruct> IDENTITYData{};
    // 附表数据
    std::vector<SubStructIDATA> subDataIDATA;
    std::vector<SubStructRDATA> subDataRDATA;

    // 2. 转换为nastran格式数据
    OwnToNastran (writeStorage, IDENTITYData, subDataIDATA, subDataRDATA);

    // 3. 写出数据至文件
    WriteData (MainDataset, IDENTITYData);
    WriteData (SubDataset_IDATA, subDataIDATA);
    WriteData (SubDataset_RDATA, subDataRDATA);

    // 4. 更新Index表
    this->WriteIndexData (this->GetIndexDatasetInfo (), writeStorage);

    // 5. 清空缓存
    writeStorage.clear ();
}

std::vector<TRANSFORMATIONRepository::DataType>*  TRANSFORMATIONRepository::LoadReadCache (std::size_t loadIndex)
{
    // 1. 读取范围内主表数据
    std::vector<NasMainStruct> IDENTITYData;
    LoadMainMetadata (loadIndex, IDENTITYData);

    if (IDENTITYData.empty ())
    {
        return nullptr;
    }

    // 2. 读取范围内附表数据
    std::vector<SubStructIDATA> subDataIDATA;
    std::vector<SubStructRDATA> subDataRDATA;

    if (!IDENTITYData.empty ())
    {
        // 获取IDENTITYData中第一个IINDEX不为0的索引位置
        std::size_t beginIndex = 0;
        for (const auto& data : IDENTITYData)
        {
            if (data.IINDEX > 0)
            {
                beginIndex = data.IINDEX;
                break;
            }
        }
        // 获取IDENTITYData中最后一个IINDEX不为0的索引
        std::size_t lastIndex = 0;
        for (const auto& data : IDENTITYData)
        {
            if (data.IINDEX > 0)
            {
                lastIndex = data.IINDEX;
            }
        }
        if (lastIndex > 0)
        {
            beginIndex -= 1;
            const std::size_t length = lastIndex - 1 + 12 - beginIndex;
            GetDataset (SubDataset_IDATA).select ({ beginIndex }, { length }).read (subDataIDATA);
        }
    }
    if (!IDENTITYData.empty ())
    {
        // 获取IDENTITYData中第一个IINDEX不为0的索引位置
        std::size_t beginIndex = 0;
        for (const auto& data : IDENTITYData)
        {
            if (data.RINDEX > 0)
            {
                beginIndex = data.RINDEX;
                break;
            }
        }
        // 获取IDENTITYData中最后一个IINDEX不为0的索引
        std::size_t lastIndex = 0;
        for (const auto& data : IDENTITYData)
        {
            if (data.RINDEX > 0)
            {
                lastIndex = data.RINDEX;
            }
        }
        if (lastIndex > 0)
        {
            beginIndex -= 1;
            const std::size_t length = lastIndex - 1 + 12 - beginIndex;
            GetDataset (SubDataset_RDATA).select ({ beginIndex }, { length }).read (subDataRDATA);
        }
    }

    // 3. 将数据转换为自己的格式放入缓存
    auto* cacheVector = m_cacheHelper.LookupOrCreateVector<DataType> (GetMainCache ().m_readCacheKey, IDENTITYData.size ());
    NastranToOwn (IDENTITYData, subDataIDATA, subDataRDATA, *cacheVector);
    return cacheVector;
}

void TRANSFORMATIONRepository::SortData ()
{
    // 1. 读取主表数据
    std::vector<NasMainStruct> IDENTITYData;
    GetDataset (MainDataset).read (IDENTITYData);

    if (IDENTITYData.empty ())
    {
        GetMainDatasetInfo ().SetIsSequential (true);
        return;
    }

    // 2. 读取附表数据
    std::vector<SubStructIDATA> subDataIDATA;
    std::vector<SubStructRDATA> subDataRDATA;

    GetDataset (SubDataset_IDATA).read (subDataIDATA);
    GetDataset (SubDataset_RDATA).read (subDataRDATA);

    // 3. 将所有数据转换
    std::vector<MainStruct> AllData{};
    NastranToOwn (IDENTITYData, subDataIDATA, subDataRDATA, AllData);

    // 4. 排序
    std::sort (AllData.begin (), AllData.end ());

    // 5. 转换回nastran格式
    OwnToNastran (AllData, IDENTITYData, subDataIDATA, subDataRDATA, true);

    // 6. 写出主表数据至文件
    GetDataset (MainDataset).write (IDENTITYData);
    // 7. 写出附表数据至文件
    GetDataset (SubDataset_IDATA).write (subDataIDATA);
    GetDataset (SubDataset_RDATA).write (subDataRDATA);

    // 8. 重写索引
    RewriteIndexData (AllData);

    // 9. 设置为已顺序
    GetMainDatasetInfo ().SetIsSequential (true);
}

std::vector<TRANSFORMATIONRepository::MainStruct> TRANSFORMATIONRepository::GetAllData ()
{
    Sort ();

    std::vector<MainStruct> result;

    std::vector<NasMainStruct> IDENTITYData;
    GetDataset (MainDataset).read (IDENTITYData);

    if (IDENTITYData.empty ())
    {
        return result;
    }

    std::vector<SubStructIDATA> subDataIDATA;
    std::vector<SubStructRDATA> subDataRDATA;

    GetDataset (SubDataset_IDATA).read (subDataIDATA);
    GetDataset (SubDataset_RDATA).read (subDataRDATA);

    // 将所有数据转换
    NastranToOwn (IDENTITYData, subDataIDATA, subDataRDATA, result);

    return result;
}

void TRANSFORMATIONRepository::OwnToNastran (std::vector<MainStruct>&          own,
                                             std::vector<NasMainStruct>& _OUT  IDENTITYData,
                                             std::vector<SubStructIDATA>& _OUT subDataIDATA,
                                             std::vector<SubStructRDATA>& _OUT subDataRDATA,

                                             bool isSort)
{
    subDataIDATA.clear ();
    subDataRDATA.clear ();

    IDENTITYData.clear ();
    IDENTITYData.reserve (own.size ());

    // 获取已有数据条数，主要是放在主表的POS字段
    // 如果是重新排序的时候，Pos都是从0 开始的
    size_t maxIIndex = isSort ? 1 : this->GetDatasetInfo (SubDataset_IDATA).GetRowCount () + 1;
    size_t maxRIndex = isSort ? 1 : this->GetDatasetInfo (SubDataset_RDATA).GetRowCount () + 1;

    // OwnIdent 代表咱们自己的数据结构
    // NasIdent 代表nastran的数据结构
    for (auto& OwnIdent : own)
    {
        // 写入附表
        subDataIDATA.insert (subDataIDATA.end (), OwnIdent.m_IDATAList.begin (), OwnIdent.m_IDATAList.end ());
        subDataRDATA.insert (subDataRDATA.end (), OwnIdent.m_RDATAList.begin (), OwnIdent.m_RDATAList.end ());

        const size_t lenIDATA = OwnIdent.m_IDATAList.size ();
        const size_t lenRDATA = OwnIdent.m_RDATAList.size ();

        // 写入IDENTITY
        NasMainStruct NasIdent{};

        NasIdent.CID       = OwnIdent.m_id;
        NasIdent.TYPE      = OwnIdent.m_TYPE;
        NasIdent.DOMAIN_ID = OwnIdent.m_domainId;

        if (lenIDATA > 0)
        {
            NasIdent.IINDEX = static_cast<I64> (maxIIndex);
            maxIIndex += lenIDATA;
        }
        if (lenRDATA > 0)
        {
            NasIdent.RINDEX = static_cast<I64> (maxRIndex);
            maxRIndex += lenRDATA;
        }
        IDENTITYData.emplace_back (NasIdent);
    }
}

void TRANSFORMATIONRepository::NastranToOwn (std::vector<NasMainStruct>&  IDENTITYData,
                                             std::vector<SubStructIDATA>& subDataIDATA,
                                             std::vector<SubStructRDATA>& subDataRDATA,

                                             std::vector<MainStruct>& _OUT own)
{
    own.clear ();
    own.reserve (IDENTITYData.size ());

    // 代表初始的Index 位置,
    // 因为数据有可能是截取了附表的一部分，所有主表中根据POS找的时候需要对应一下，
    // 比如第一个主表数据中POS字段为10000， 附表的vector的数据
    // 就是从附表中的第10000个开始对应的 也就是Index==0的
    // const I64 index = IDENTITYData[0].POS;

    MainStruct const tempown;
    own.resize (IDENTITYData.size (), tempown);

    for (size_t i = 0; i < IDENTITYData.size (); i++)
    {
        auto& OwnIdent = own[i];
        auto& NasIdent = IDENTITYData[i];

        OwnIdent.m_id       = NasIdent.CID;
        OwnIdent.m_TYPE     = NasIdent.TYPE;
        OwnIdent.m_domainId = NasIdent.DOMAIN_ID;

        if (NasIdent.IINDEX != 0)
        {
            OwnIdent.m_IDATAList.assign (subDataIDATA.begin () + NasIdent.IINDEX - IDENTITYData[0].IINDEX,
                                         subDataIDATA.begin () + NasIdent.IINDEX + 12 - IDENTITYData[0].IINDEX);
        }
        if (NasIdent.RINDEX != 0)
        {
            OwnIdent.m_RDATAList.assign (subDataRDATA.begin () + NasIdent.RINDEX - IDENTITYData[0].RINDEX,
                                         subDataRDATA.begin () + NasIdent.RINDEX + 12 - IDENTITYData[0].RINDEX);
        }
    }
}
